// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#if defined (_WIN32)
#include <windows.h>
#include <shellapi.h>
#elif defined (__APPLE__)
#include <Carbon/Carbon.h>
#else  // __unix
#include <QProcess>
#include <QMessageBox>
#endif  // __unix

#include <QtGui/QAbstractTextDocumentLayout>

#include "ui/browser.h"
#include "util/common.h"

namespace popdiag {

Browser::Browser(QWidget *parent, const QSize &size)
  : QTextBrowser(parent), size_(size) {
  setFrameStyle(QFrame::NoFrame);
  setReadOnly(true);
  setContextMenuPolicy(Qt::NoContextMenu);
  CHECK(connect(this,
                SIGNAL(anchorClicked(const QUrl &)),
                this,
                SLOT(LaunchUrl(const QUrl &))));
  CHECK(connect(this,
                SIGNAL(anchorClicked(const QUrl &)),
                this,
                SLOT(CancelNavigation())));
  CHECK(connect(this,
                SIGNAL(textChanged()),
                this,
                SLOT(ResizeToFitText())));
}

Browser::~Browser() {
}

QSize Browser::sizeHint() {
  return size_;
}

void Browser::CancelNavigation() {
  setSource(source());
}

void Browser::ResizeToFitText() {
  QSize hint = sizeHint();
  QSize now = size();
  setMaximumSize(hint);
}

void Browser::LaunchUrl(const QUrl &url) {
  LaunchUrlInNativeBrowser(url);
}

#if defined (__APPLE__)
void Browser::LaunchUrlInNativeBrowser(const QUrl &url) {
  ICInstance ic;
  // must be 4 ascii characters:
  OSType creator_id = 'Gmal';
  // Start the internet config service.  If it fails, we can't
  // launch a browser.  Oh well.
  OSStatus error = ICStart(&ic, creator_id);
  if (error == noErr) {
    ConstStr255Param null_hint(0);
    QByteArray url_byte_array = qPrintable(url.toString());
    const char *url_bytes = url_byte_array.data();
    int length = url_byte_array.length();
    // API wants the range of the passed in byte array that
    // represents the URL.  We want the whole thing.
    long start = 0;
    long end = length;
    ICLaunchURL(ic, null_hint, url_bytes, length, &start, &end);
    // browser will report any errors.
    ICStop(ic);
  }
}

#elif defined (_WIN32)

void Browser::LaunchUrlInNativeBrowser(const QUrl &url) {
  QString in = url.toString();
  // ShellExecute isn't doing the right thing with file URLs.
  // So we'll fix up the document path ourselves.
  const QString file_prefix = "file:///";
  if (in.startsWith(file_prefix)) {
    QString path_decoded = QUrl::fromPercentEncoding(
        qPrintable(in.mid(file_prefix.size())));
    in = path_decoded.replace("/", "\\");
  }
  int max_len = in.length() + 1;
  scoped_ptr<wchar_t> buffer(new wchar_t[max_len]);
  for (int i = 0; i < in.length(); i++) {
    (buffer.get())[i] = in[i].unicode();
  }
  (buffer.get())[i] = '\0';

  ShellExecute(NULL, L"open", buffer.get(), NULL, NULL, 0);
}

#else  // __unix

void Browser::LaunchUrlInNativeBrowser(const QUrl &url) {
  // TODO: Try to determine the user's preference here.
  QString browser = "firefox";
  process_ = new QProcess();
  QStringList args = (QStringList() << url.toString());

  CHECK(connect(process_, SIGNAL(finished(int, QProcess::ExitStatus)),
                this, SLOT(OnProcessExit(int, QProcess::ExitStatus))));
  CHECK(connect(process_, SIGNAL(error(QProcess::ProcessError)),
                this, SLOT(OnProcessError(QProcess::ProcessError))));

  process_->start(browser, args);
}

#endif  // __unix

// The following #ifdefs are quite ugly, but if they are put
// around the function declarations, moc will not find the slots,
// and a run-time error occurs.
void Browser::OnProcessExit(int code, QProcess::ExitStatus /*status*/) {
#ifdef __unix
  if (code != 0) {
    QMessageBox::warning(this, tr("POP and IMAP Troubleshooter"),
                        tr("The web browser returned with an error"),
                        QMessageBox::Close,
                        QMessageBox::Close);
  }
  delete process_;
#endif  // __unix
}

void Browser::OnProcessError(QProcess::ProcessError /*error*/) {
#ifdef __unix
  QMessageBox::warning(this, tr("POP and IMAP Troubleshooter"),
                       tr("Failed to execute the web browser"),
                       QMessageBox::Close,
                       QMessageBox::Close);
  delete process_;
#endif  // __unix
}

}  // namespace popdiag
